package org.ccay.validator.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.ccay.core.log.CcayLoggerFactory;
import org.ccay.core.log.ILogger;
import org.ccay.core.util.StringUtil;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.spring.SpringObjectFactory;
import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
import com.opensymphony.xwork2.validator.ShortCircuitableValidator;
import com.opensymphony.xwork2.validator.Validator;
import com.opensymphony.xwork2.validator.ValidatorConfig;
import com.opensymphony.xwork2.validator.ValidatorFactory;

/**
 * Default validator factory
 *
 * @author chaowangbang
 */
public class DefaultValidatorFactory implements ValidatorFactory, ApplicationContextAware {
	
	/**
	 * 日志记录器
	 */
	private ILogger logger = CcayLoggerFactory.getLogger(DefaultValidatorFactory.class);
	
	private static final String VALIDATOR_NAME_SUFFIX = "Validator";
	
	protected ApplicationContext ctx;

    protected Map<String, String> validators = new HashMap<String, String>();
    protected SpringObjectFactory objectFactory;
    protected Container container;
    protected ReflectionProvider reflectionProvider;
    
    @Inject
    public void setContainer(Container container) {
        this.container = container;
    }
    
    @Inject
    public void setReflectionProvider(ReflectionProvider prov) {
        this.reflectionProvider = prov;
    }

	@Inject
	public DefaultValidatorFactory(@Inject ObjectFactory objectFactory) {
        this.objectFactory = (SpringObjectFactory)objectFactory;
        this.objectFactory.autoWireBean(this);
		// 增加框架自定义部分
        loadDefaultValidators();
	}
	
	/* (non-Javadoc)
	 * @see com.opensymphony.xwork2.validator.ValidatorFactory#getValidator(com.opensymphony.xwork2.validator.ValidatorConfig)
	 */
	public Validator getValidator(ValidatorConfig cfg) {
		String classId = cfg.getType() + VALIDATOR_NAME_SUFFIX;
        Validator validator;

        try {
            // instantiate the validator, and set configured parameters
        	validator = ctx.getBean(classId, Validator.class);
        	container.inject(validator);
        	reflectionProvider.setProperties(cfg.getParams(), validator);
        } catch (Exception e) {
        	final String msg = "There was a problem creating a Validator of id " + classId + " : caused by " + e.getMessage();
        	logger.error(msg, e);
            throw new XWorkException(msg, e, cfg);
        }

        // set other configured properties
        String cfgMessageKey = cfg.getMessageKey();
        // 配置了message key时，选择配置文件的key
        if ( !StringUtil.isNullOrEmpty(cfgMessageKey) ) {
            validator.setMessageKey(cfg.getMessageKey());
        }
        validator.setDefaultMessage(cfg.getDefaultMessage());
        validator.setMessageParameters(cfg.getMessageParams());
        if (validator instanceof ShortCircuitableValidator) {
            ((ShortCircuitableValidator) validator).setShortCircuit(cfg.isShortCircuit());
        }

        return validator;
	}

	/**
	 * 根据验证器名字查找验证器的id
	 * @param name
	 */
	public String lookupRegisteredValidatorType(String name) {
        // lookup the validator id mapped to the type name
		String classId = name + VALIDATOR_NAME_SUFFIX;
        String className = validators.get(classId);

        if (className == null) {
            throw new IllegalArgumentException("There is no validator class mapped to the id " + classId);
        }
        return className;
	}

	/**
	 * 在xwork框架的默认处理后，读取ccay框架默认配置文件
	 * 最后读取项目组定制文件
	 */
	private void loadDefaultValidators() {
		// 加载验证器信息
		Map<String, Validator> validatorList = ctx.getBeansOfType(Validator.class);
		buildValidators(validatorList);
	}

	/**
	 * 注册验证类型
	 * @param name 验证器名称
	 * @param className 验证器类名
	 */
	public void registerValidator(String name, String className) {
		String classId = name + VALIDATOR_NAME_SUFFIX;
        if (logger.isDebugEnabled()) {
        	logger.debug("Registering validator of class " + className + " with id " + classId);
        }
        validators.put(classId, className);
    }
	
	/**
	 * 加载验证器信息
	 * @param defaultValidators
	 */
	private void buildValidators(Map<String, Validator> validatorList) {
		for ( Entry<String, Validator> entry : validatorList.entrySet() ) {
			Validator v = entry.getValue();
            String name = entry.getKey();
            String className = v.getClass().getName();
            validators.put(name, className);
		}
	}

	/* (non-Javadoc)
	 * @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
	 */
	public void setApplicationContext(ApplicationContext context) throws BeansException {
		this.ctx = context;
	}
	
}
